/*
@title: Kill-the-snek
@author: CodeWhiteWeb
@tags: ['maze', 'puzzle', 'retro']
@addedOn: None
@description: Snake-style game but with Smart Enemy, multiple levels, and obstacles.
*/

const player = "p";
const enemy = "e";
const wall = "w";
const obstacle = "o";

setLegend(
  [player, bitmap`
..050000000050..
.05500000000550.
0555555555555550
5555555555555555
0055000000005500
0055000000005500
0055000000005500
0055000000005500
0055000000005500
0055000000005500
0055000000005500
0055000000005500
5555555555555555
0555555555555550
.05500000000550.
..050000000050..`],
  [enemy, bitmap`
..030000000030..
.03300000000330.
0333333333333330
3333333333333333
0033000000003300
0033000000003300
0033000000003300
0033000000003300
0033000000003300
0033000000003300
0033000000003300
0033000000003300
3333333333333333
0333333333333330
.03300000000330.
..030000000030..`],
  [wall, bitmap`
7777777777777777
7055555555555507
7500000000000057
7500777777770057
7507555555557057
7507555555557057
7507555555557057
7507555555557057
7507555555557057
7507555555557057
7507555555557057
7507555555557057
7500777777770057
7500000000000057
7055555555555507
7777777777777777`],
  [obstacle, bitmap`
0000000000000000
0077777777777700
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0777777777777770
0077777777777700
0000000000000000`]
);

setSolids([wall, obstacle]);

const levels = [
  map`
...................
...................
...................
...................
...................
...................
...................
...................
...................
...................
...................
...................
...................
...................`,
  map`
...................
...................
...................
...................
...................
...................
...................
.......w.....o.....
...................
...................
...................
...................
...................
...................`,
  map`
...................
..w..........w.....
..............w....
...................
...................
...................
...................
...................
...................
...................
......w........w...
...................
...................
...................`,
  map`
...................
...................
...w.......o.......
...w...............
...................
...................
...................
...................
............w......
...........w.......
...................
...................
...................
...................`,
  map`
..........o........
.o.................
...................
...................
...............o...
...................
........w..........
...................
...................
...................
...w...o...........
..............w....
...................
...................`,
  map`
...................
...................
.....w........o....
...................
...................
..o................
...................
.......w.....o.....
...................
...................
...............o...
...................
...................
.........www.......`,
  map`
.oo................
..o................
..w........o....w..
...................
...................
...................
...................
.......w.....o.....
...................
...................
...................
.......o...........
w..w....o..........
..................w`,
  map`
.w.................
.............w.....
...................
.......o...........
....w............o.
...................
...................
w......w.....o.....
...................
...................
...................
.w......o..........
...........w.....o.
.....w.............`,
  map`
...................
.w....w.......o..w.
...................
........w...o......
.o.................
...................
...............o...
...................
....o..............
.......o...........
..o........w.....o.
...................
.w...............w.
.............o.....`,
  map`
......w.w.ooo...o..
......w.w..w....w..
......w.w..o....w..
......w.w..w....oo.
......w.w.ooo......
...................
...................
...................
...................
...................
......o...ooww.....
wwoo..w........o...
...o..o........w..o
...o...........wwoo`,
  map`
ww.oooo.ww..wwww.oo
w.................o
...................
w.................o
w.................o
...................
o.................w
o.................w
o.................w
o.................w
...................
w.................o
w.................o
ww.pppp.oo..oooo.oo`,
  map`
...................
.ww..w...ooooo.....
.............o.....
.............o.....
.............o.....
...................
...................
...................
...................
...................
......w............
......w............
...................
.......ww..........`
];



let level = 0;
setMap(levels[level]);

setPushables({
  [player]: [],
  [enemy]: []
});

let playerTrail = [];
let enemyTrail = [];
let direction = { x: 1, y: 0 };
let enemyDir = { x: -1, y: 0 };
let isGameOver = false;

addSprite(2, 7, player);
playerTrail.push({ x: 2, y: 7 });
addSprite(15, 7, enemy);
enemyTrail.push({ x: 15, y: 7 });

onInput("w", () => direction = { x: 0, y: -1 });
onInput("a", () => direction = { x: -1, y: 0 });
onInput("s", () => direction = { x: 0, y: 1 });
onInput("d", () => direction = { x: 1, y: 0 });
onInput("k", restartGame);

function wrap(pos) {
  return {
    x: (pos.x + width()) % width(),
    y: (pos.y + height()) % height()
  };
}

function move(sprite, trail, dir) {
  const head = wrap({ x: trail[0].x + dir.x, y: trail[0].y + dir.y });
  if (getTile(head.x, head.y).some(t => t.type === player || t.type === enemy || t.type === wall || t.type === obstacle)) return null;
  addSprite(head.x, head.y, sprite);
  trail.unshift(head);
  return head;
}

function gameOver(win) {
  isGameOver = true;
  clearInterval(gameInterval);
  clearText();
  addText(win ? "YOU WIN!" : "GAME OVER", { x: 5, y: 7, color: color`3` });
  addText("Press K to Restart", { x: 2, y: 9, color: color`0` });
}

function restartGame() {
  level = 0;
  startLevel();
}

function clearBoard() {
  clearText();
  for (let y = 0; y < height(); y++) {
    for (let x = 0; x < width(); x++) {
      const tile = getTile(x, y);
      tile.forEach(s => s.remove());
    }
  }
}

function startLevel() {
  isGameOver = false;
  clearBoard();
  setMap(levels[level]);
  playerTrail = [{ x: 2, y: 7 }];
  enemyTrail = [{ x: 15, y: 7 }];
  direction = { x: 1, y: 0 };
  enemyDir = { x: -1, y: 0 };
  addSprite(2, 7, player);
  addSprite(15, 7, enemy);
  gameInterval = setInterval(step, 200);
}

function getSafeDirs(pos) {
  const dirs = [
    { x: 1, y: 0 },
    { x: -1, y: 0 },
    { x: 0, y: 1 },
    { x: 0, y: -1 }
  ];
  return dirs.filter(d => {
    const { x, y } = wrap({ x: pos.x + d.x, y: pos.y + d.y });
    const tile = getTile(x, y);
    return tile.every(t => t.type !== player && t.type !== enemy && t.type !== wall && t.type !== obstacle);
  });
}

function step() {
  if (isGameOver) return;

  const newPlayer = move(player, playerTrail, direction);
  if (!newPlayer) return gameOver(false);

  const enemyPos = enemyTrail[0];
  const options = getSafeDirs(enemyPos);
  if (options.length === 0) return nextLevel();

  enemyDir = options[Math.floor(Math.random() * options.length)];
  const newEnemy = move(enemy, enemyTrail, enemyDir);
  if (!newEnemy) return nextLevel();
}

function nextLevel() {
  level++;
  if (level >= levels.length) {
    clearText();
    addText('ALL LEVELS DONE!\n YOU WIN!', { x: 2, y: 7, color: color`H` });
    clearInterval(gameInterval);
    return;
  }
  clearInterval(gameInterval);
  startLevel();
}

let gameInterval = setInterval(step, 200);